package org.jeecg.modules.gyy.controller;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CacheConstant;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.Md5Util;
import org.jeecg.common.util.PasswordUtil;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.JeecgBaseConfig;
import org.jeecg.modules.gyy.Dto.PcLoginModel;
import org.jeecg.modules.gyy.common.CommonUtils;
import org.jeecg.modules.gyy.gyyuser.entity.GyyUser;
import org.jeecg.modules.gyy.gyyuser.service.IGyyUserService;
import org.jeecg.modules.gyy.service.PcUserService;
import org.jeecg.modules.gyy.vo.UserModel;
import org.jeecg.modules.system.util.RandImageUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.web.bind.annotation.*;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;

import javax.annotation.Resource;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDate;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.UUID;

/**
 * @Description: 用户接口
 * @Author: L
 * @Date:   2024-11-27
 * @Version: V1.0
 */
@Api(tags="用户接口")
@RestController
@RequestMapping("/pc/user")
@Slf4j
public class PcUserController {

    @Autowired
    private IGyyUserService iGyyUserService;

    @Resource
    private PcUserService pcUserService;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired(required = false)
    private JavaMailSender sender;

    @Autowired(required = false)
    private TemplateEngine templateEngine;

    @Autowired
    private JeecgBaseConfig jeecgBaseConfig;

    @Value(value = "${spring.mail.username}")
    private String sendFrom;

    private final String BASE_CHECK_CODES = "qwertyuiplkjhgfdsazxcvbnmQWERTYUPLKJHGFDSAZXCVBNM1234567890";

    /**
     * pc登录接口
     * @param pcLoginModel
     * @return
     */
    @ApiOperation("pc登录接口")
    @RequestMapping(value = "/pcLogin", method = RequestMethod.POST)
    public Result<JSONObject> pcLogin(@RequestBody PcLoginModel pcLoginModel) {
        Result<JSONObject> result = new Result<JSONObject>();
        String username = pcLoginModel.getUsername();
        String code = pcLoginModel.getCaptcha();
//        String password = pcLoginModel.getPassword();


//        if (StrUtil.isBlank(username) || StrUtil.isBlank(password)) {
//            result.error500("账号或密码不能为空");
//            return result;
//        }
//        String captcha = pcLoginModel.getCaptcha();
//        if(captcha==null){
//            result.error500("验证码无效");
//            return result;
//        }
//        String lowerCaseCaptcha = captcha.toLowerCase();
//        String origin = lowerCaseCaptcha+pcLoginModel.getCheckKey()+jeecgBaseConfig.getSignatureSecret();
//        String realKey = Md5Util.md5Encode(origin, "utf-8");
//        Object checkCode = redisUtil.get(realKey);
//        if(checkCode==null || !checkCode.toString().equals(lowerCaseCaptcha)) {
//            log.warn("验证码错误，key= {} , Ui checkCode= {}, Redis checkCode = {}", pcLoginModel.getCheckKey(), lowerCaseCaptcha, checkCode);
//            result.error500("验证码错误");
//            result.setCode(HttpStatus.PRECONDITION_FAILED.value());
//            return result;
//        }

        //1. 校验用户是否有效
        GyyUser user = pcUserService.getUserByName(username);
        if (user == null) {
            String randomValue = UUID.randomUUID().toString().replace("-", "").substring(0, 8);  // 取UUID的前8位作为随机值
            GyyUser newUser = new GyyUser();
            newUser.setCreateTime(new Date());// 设置创建时间
            String salt = oConvertUtils.randomGen(8);
            String passwordEncode = PasswordUtil.encrypt(username, username, salt);
            newUser.setSalt(salt);
            newUser.setUsername(username);
            newUser.setNikename("gyy"+randomValue);
            newUser.setPassword(passwordEncode);
            newUser.setEmail(username);
            newUser.setStatus(1);
            iGyyUserService.save(newUser);
            userInfo(newUser, result);
            return result;
        }
        if (user.getStatus() == 0) {
            result.error500("该用户已被冻结");
            return result;
        }
        if (code == null) {
            result.error500("验证码无效");
            return result;
        }
        // 比较验证码
        String redisKey = CommonConstant.EMAIL_REDIS_KEY_PRE + username;
        Object checkCode = redisUtil.get(redisKey);
        if (!code.equals(checkCode.toString())) {
            result.error500("验证码错误");
            return result;
        }
//        //2. 校验用户名或密码是否正确
//        String userpassword = PasswordUtil.encrypt(username, password, user.getSalt());
//        String syspassword = user.getPassword();
//        if (!syspassword.equals(userpassword)) {
//            result.error500("账号或密码错误");
//            return result;
//        }
        userInfo(user, result);
        return result;
    }


    /**
     * 用户注册接口邮箱
     * @param jsonObject
     * @return
     */
    @ApiOperation("pc用户注册接口")
    @PostMapping("/register")
    public Result<JSONObject> userRegister(@RequestBody JSONObject jsonObject) {
        Result<JSONObject> result = new Result<JSONObject>();
        String email = jsonObject.getString("email");
		String code = jsonObject.getString("code");

//		String redisKey = CommonConstant.PHONE_REDIS_KEY_PRE + phone;
//		Object code = redisUtil.get(redisKey);

        // 邮箱不能为空
        if (oConvertUtils.isEmpty(email)) {
            result.setMessage("账号不能为空");
            result.setSuccess(false);
            return result;
        }
        //未设置密码，则默认123456
        String password = jsonObject.getString("password");
        if (oConvertUtils.isEmpty(password)) {
//			password = RandomUtil.randomString(8);
            password = "123456a";
        }

		// *--- start 2024-2-5 11:30 @Author:L 验证码验证 ---*
		if (code == null) {
			result.error500("验证码无效");
			return result;
		}
		// 比较验证码
		String redisKey = CommonConstant.EMAIL_REDIS_KEY_PRE + email;
		Object checkCode = redisUtil.get(redisKey);
		if (!code.equals(checkCode.toString())) {
			result.error500("验证码错误");
			return result;
		}
		// *--- end 2024-2-5 11:30 @Author:L 验证码验证 ---*

        // 判断邮箱是否被注册
        GyyUser user1 = pcUserService.getUserByName(email);
        if (user1 != null) {
            result.setMessage("邮箱已注册");
            result.setSuccess(false);
            return result;
        }

        // 生成随机的用户名，格式为 "kd+随机值"
        String randomValue = UUID.randomUUID().toString().replace("-", "").substring(0, 8);  // 取UUID的前8位作为随机值

        try {
            GyyUser user = new GyyUser();
            user.setCreateTime(new Date());// 设置创建时间
            String salt = oConvertUtils.randomGen(8);
            String passwordEncode = PasswordUtil.encrypt(email, password, salt);
            user.setSalt(salt);
            user.setUsername(email);
            user.setNikename("kd"+randomValue);
            user.setPassword(passwordEncode);
            user.setEmail(email);
            user.setStatus(1);
            iGyyUserService.save(user);

            result.success("注册成功");
        } catch (Exception e) {
            result.error500("注册失败");
        }
        return result;
    }


    /**
     * 发送qq短信接口
     * @param jsonObject
     * @return
     */
    @ApiOperation("pc发送qq短信接口")
    @PostMapping(value = "/sms")
    public Result<String> sms(@RequestBody JSONObject jsonObject) throws MessagingException {
        // 返回结果
        Result<String> result = new Result<String>();
        // 邮箱
        String email = jsonObject.getString("email");

        // 1.判断邮箱是否为空
        if (oConvertUtils.isEmpty(email)) {
            result.error500("邮箱不能为空");
            return result;
        }

        // 2.校验邮箱格式
        if (!CommonUtils.emailVerification(email)) {
            result.error500("邮箱格式不正确");
            return result;
        }

        // 3.校验邮箱验证码是否有效
        String emailKey = CommonConstant.EMAIL_REDIS_KEY_PRE + email;
        Object object = redisUtil.get(emailKey);
        if (object != null) {
            result.setMessage("验证码5分钟内，仍然有效！");
            result.setSuccess(false);
            return result;
        }

        // 4.生成一个 5 位的验证码
        String code = UUID.randomUUID().toString().toUpperCase().replace("-", "").substring(0, 5);
        redisUtil.set(emailKey, code, 60 * 5);

        // 5.创建一个 MimeMessage 对象，用于构造邮件
        MimeMessage mailMessage = sender.createMimeMessage();
        // true 表示邮件支持多部分（如 HTML）
        MimeMessageHelper helper = new MimeMessageHelper(mailMessage, true);
        //邮件的主题
        helper.setSubject("口袋视频Email验证码");
        //邮件的内容
        //创建 指定关键字   并设定值
        Context context = new Context();
        // 设置 "username" 变量，模板中将会使用该变量
        context.setVariable("username", "口袋用户");
        // 设置 "code" 变量，模板中将会使用该验证码
        context.setVariable("code", code);
        //指定对应html模板,并放入context对象
        String emailContent= templateEngine.process("mail", context);
        // 将渲染好的 HTML 内容设置到邮件的正文
        helper.setText(emailContent,true);
        // 设置邮件的接收者和发送者的邮箱地址
        helper.setTo(email);       // 接收者的邮箱
        helper.setFrom(sendFrom);  // 发送者的邮箱
        //发送邮件
        sender.send(mailMessage);
        // 生成token,并封装map返回
        JSONObject resultData = new JSONObject();
        // 生成token
        String token = JwtUtil.sign(email, email);
        redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
        // 设置超时时间
        redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, 60 * 5);
        resultData.put("token", token);
        result.setResult(resultData.toString());
        result.setMessage("发送成功");
        result.setSuccess(true);
        result.setCode(200);
        return result;
    }


    /**
     * pc用户重置密码
     */
    @ApiOperation("pc用户重置密码接口")
    @RequestMapping(value = "/updatePassword", method = RequestMethod.POST)
    public Result<?> updatePassword(@RequestBody JSONObject json) throws Exception {
        String username = json.getString("username");
        String oldpassword = json.getString("oldpassword");
        String password = json.getString("password");
        String confirmpassword = json.getString("confirmpassword");

        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        if (!sysUser.getUsername().equals(username)) {
            return Result.error("只允许修改自己的密码！");
        }
        GyyUser user = pcUserService.getUserByName(username);
        if (user == null) {
            return Result.error("用户不正确！");
        }
        return pcUserService.resetPassword(username, oldpassword, password, confirmpassword);
    }


    /**
     * 后台生成图形验证码 ：有效
     * @param response
     * @param key
     */
    @ApiOperation("获取验证码")
    @GetMapping(value = "/randomImage/{key}")
    public Result<String> randomImage(HttpServletResponse response,@PathVariable("key") String key){
        Result<String> res = new Result<String>();
        try {
            //生成验证码
            String code = RandomUtil.randomString(BASE_CHECK_CODES,4);
            //存到redis中
            String lowerCaseCode = code.toLowerCase();

            //update-begin-author:taoyan date:2022-9-13 for: VUEN-2245 【漏洞】发现新漏洞待处理20220906
            // 加入密钥作为混淆，避免简单的拼接，被外部利用，用户自定义该密钥即可
            String origin = lowerCaseCode+key+jeecgBaseConfig.getSignatureSecret();
            String realKey = Md5Util.md5Encode(origin, "utf-8");
            //update-end-author:taoyan date:2022-9-13 for: VUEN-2245 【漏洞】发现新漏洞待处理20220906

            redisUtil.set(realKey, lowerCaseCode, 60);
            log.info("获取验证码，Redis key = {}，checkCode = {}", realKey, code);
            //返回前端
            String base64 = RandImageUtil.generate(code);
            res.setSuccess(true);
            res.setResult(base64);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            res.error500("获取验证码失败,请检查redis配置!");
            return res;
        }
        return res;
    }


    /**
     * 个人中心修改用户信息
     * @param jsonObject
     * @return
     */
    @ApiOperation("个人中心修改用户信息")
    @RequestMapping(value = "/editUserInfo", method = {RequestMethod.PUT, RequestMethod.POST})
    public Result<GyyUser> editUserInfo(HttpServletRequest request, @RequestBody JSONObject jsonObject) {
        Result<GyyUser> result = new Result<GyyUser>();
        try {
            String username = JwtUtil.getPCUserNameByToken(request);
            GyyUser kdUser = pcUserService.getUserByName(username);
            String nikename = jsonObject.getString("nikename");

            // 判断用户是否存在
            if (kdUser == null) {
                result.error500("未找到对应用户!");
                return result;
            }

            // 获取前端传来的数据
            String signature = jsonObject.getString("signature");
            Integer sex = jsonObject.getInteger("sex");
            Date birthday = jsonObject.getDate("birthday");
            String phone = jsonObject.getString("phone");
            String school = jsonObject.getString("school");

            // 更新用户信息
            if (StringUtils.isNotBlank(nikename)) {
                kdUser.setNikename(nikename);
            }
            if (StringUtils.isNotBlank(signature)) {
                kdUser.setSignature(signature);
            }
            if (sex != null) {
                kdUser.setSex(sex);
            }
            if (StringUtils.isNotBlank(phone)) {
                kdUser.setPhone(phone);
            }
            if (birthday != null) {
                kdUser.setBirthday(birthday);
            }

            // 更新修改时间
            kdUser.setUpdateTime(new Date());

            // 执行更新
            iGyyUserService.updateById(kdUser);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            result.error500("保存失败!");
        }
        return result;
    }


    @ApiOperation("修改用户头像")
    @RequestMapping(value = "/updateUserAvatar", method = {RequestMethod.PUT, RequestMethod.POST})
    public Result<GyyUser> updateUserAvatar(HttpServletRequest request, @RequestBody JSONObject jsonObject) {
        Result<GyyUser> result = new Result<GyyUser>();
        try {
            String username = JwtUtil.getPCUserNameByToken(request);
            GyyUser kdUser = pcUserService.getUserByName(username);

            // 判断用户是否存在
            if (kdUser == null) {
                result.error500("未找到对应用户!");
                return result;
            }

            // 获取前端传来的头像URL
            String avatar = jsonObject.getString("avatar");

            // 更新用户头像
            if (StringUtils.isNotBlank(avatar)) {
                kdUser.setAvatar(avatar);
            }

            // 更新修改时间
            kdUser.setUpdateTime(new Date());

            // 执行更新
            iGyyUserService.updateById(kdUser);

            // 返回成功结果
            result.setSuccess(true);
            result.setMessage("头像更新成功!");
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            result.error500("更新头像失败!");
        }
        return result;
    }


    /**
     * pc用户邮箱重置密码
     */
    @ApiOperation("pc用户邮箱重置密码")
    @RequestMapping(value = "/emailUpdatePwd", method = RequestMethod.POST)
    public Result<?> emailUpdatePwd(@RequestBody JSONObject json) throws Exception {
        String username = json.getString("username");
        String password = json.getString("password");
        String confirmpassword = json.getString("confirmpassword");

        // *--- start 2024-2-5 11:30 @Author:L 验证码验证 ---*
        String code = json.getString("code");
        Result<JSONObject> result = new Result<JSONObject>();
        if (code == null) {
            result.error500("验证码无效");
            return result;
        }
        // 比较验证码
        String redisKey = CommonConstant.EMAIL_REDIS_KEY_PRE + username;
        Object checkCode = redisUtil.get(redisKey);
        if (!code.equals(checkCode.toString())) {
            result.error500("验证码错误");
            return result;
        }
        // *--- end 2024-2-5 11:30 @Author:L 验证码验证 ---*

        GyyUser user = pcUserService.getUserByName(username);
        if (user == null) {
            return Result.error("用户不正确！");
        }
        return pcUserService.forgetPassword(username, password, confirmpassword);
    }


    /**
     * pc退出登录
     * @param request
     * @param response
     * @return
     */
    @ApiOperation("pc退出登录")
    @RequestMapping(value = "/logout",method = RequestMethod.POST)
    public Result<Object> logout(HttpServletRequest request, HttpServletResponse response) {
        //用户退出逻辑
        String token = request.getHeader(CommonConstant.PC_TOKEN);
        if(oConvertUtils.isEmpty(token)) {
            return Result.error("退出登录失败！");
        }
        String username = JwtUtil.getUsername(token);
        GyyUser user = pcUserService.getUserByName(username);
        if(user!=null) {
            log.info(" 用户名:  "+user.getNikename()+",退出成功！ ");
            //清空用户登录Token缓存
            redisUtil.del(CommonConstant.PREFIX_USER_TOKEN + token);
            //清空用户登录Shiro权限缓存
            redisUtil.del(CommonConstant.PREFIX_USER_SHIRO_CACHE + user.getId());
            //清空用户的缓存信息（包括部门信息），例如sys:cache:user::<username>
            redisUtil.del(String.format("%s::%s", CacheConstant.SYS_USERS_CACHE, user.getUsername()));
            //调用shiro的logout
            SecurityUtils.getSubject().logout();
            return Result.ok("退出登录成功！");
        }else {
            return Result.error("Token无效!");
        }
    }


    /**
     * 用户信息
     * @param user
     * @param result
     * @return
     */
    private Result<JSONObject> userInfo(GyyUser user, Result<JSONObject> result) {
        String username = user.getUsername();
        String password = user.getPassword();
        // 获取用户部门信息
        JSONObject obj = new JSONObject(new LinkedHashMap<>());

        //1.生成token
        String token = JwtUtil.sign(username, username);
        // 设置token缓存有效时间
        redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
        redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME * 2 / 1000);
        obj.put("token", token);

        UserModel userModel = new UserModel();
        BeanUtils.copyProperties(user, userModel);
        obj.put("userInfo", userModel);

        result.setResult(obj);
        result.setCode(200);
        result.setSuccess(true);
        result.setMessage("登录成功");
        return result;
    }
}
